import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from ttkbootstrap.dialogs.dialogs import Messagebox

import enum

from model import *

class Opr(enum.Enum):
    """ 对话框枚举类型 """
    INSERT = 1
    UPDATE = 2

class ClassDialog(ttk.Toplevel):
    """ 班级管理对话框，提供添加班级和修改班级对话框 """

    def __init__(self, title="ttkbootstrap", type: Opr=Opr.INSERT, cls: Clazz=None, callback=None, iconphoto='', size=None, position=None, minsize=None, maxsize=None, resizable=None, transient=None, overrideredirect=False, windowtype=None, topmost=False, toolwindow=False, alpha=1, **kwargs):
        """
            参数说明：
                type (Opr)：枚举，对话框类型，默认为 INSERT
                cls (Clazz)：班级信息，只有当 isupdate=True 时有效
                callback (function)：回调函数，用于成功后执行自定义操作
        """
        super().__init__(title, iconphoto, size, position, minsize, maxsize, resizable, transient, overrideredirect, windowtype, topmost, toolwindow, alpha, **kwargs)
        if Opr.INSERT == type:
            self._add_class_dialog(callback)
        elif Opr.UPDATE == type:
            self._update_class_dialog(cls, callback)

    def _add_class_dialog(self, callback=None):
        """ 添加班级对话框 """
        content_frame = ttk.Frame(self)
        content_frame.pack(fill=X, pady=1, side=TOP)
        ttk.Label(content_frame, text="班级名称").pack(side=LEFT, padx=20, pady=20)
        name_ent = ttk.Entry(content_frame)
        name_ent.pack(side=LEFT)

        buttonbar = ttk.Frame(self)
        buttonbar.pack(fill=X, pady=1, side=BOTTOM)
        btn = ttk.Button(
            master=buttonbar,
            text="取消",
            style=SECONDARY,
            command=self.destroy
        )
        btn.pack(side=RIGHT, ipadx=5, ipady=5, padx=(10, 15))
        btn = ttk.Button(
            master=buttonbar,
            text="确定",
            command=lambda: self._save(name_ent.get(), callback)
        )
        btn.pack(side=RIGHT, ipadx=5, ipady=5, padx=(2, 0))

    def _save(self, classname: str=None, callback=None):
        """ 保存班级 """
        if self._validate(classname):
            cls = Clazz(name=classname)
            cls.save()
            Messagebox.ok("添加班级成功", title="消息", parent=self)
            self.destroy()

            if None != callback:
                callback()

    def _update_class_dialog(self, cls: Clazz=None, callback=None):
        """ 修改班级对话框 """
        content_frame = ttk.Frame(self)
        content_frame.pack(fill=X, pady=1, side=TOP)
        ttk.Label(content_frame, text="班级名称").pack(side=LEFT, padx=20, pady=20)
        name_ent = ttk.Entry(content_frame)
        name_ent.pack(side=LEFT)
        name_ent.insert(0, cls.name)

        buttonbar = ttk.Frame(self)
        buttonbar.pack(fill=X, pady=1, side=BOTTOM)
        btn = ttk.Button(
            master=buttonbar,
            text="取消",
            style=SECONDARY,
            command=self.destroy
        )
        btn.pack(side=RIGHT, ipadx=5, ipady=5, padx=(10, 15))
        btn = ttk.Button(
            master=buttonbar,
            text="确定",
            command=lambda: self._update(cls=Clazz(id=cls.id, name=name_ent.get()), callback=callback)
        )
        btn.pack(side=RIGHT, ipadx=5, ipady=5, padx=(2, 0))

    def _update(self, cls: Clazz=None, callback=None):
        """ 修改班级 """
        if self._validate(cls.name):
            qry = Clazz.update({Clazz.name: cls.name}).where(Clazz.id==cls.id)
            qry.execute()
            # 同步修改学生表中的班级名称
            qry = Student.update({Student.clazzname: cls.name}).where(Student.clazzid==cls.id)
            qry.execute()
            Messagebox.ok("修改班级成功", title="消息", parent=self)
            self.destroy()

            if None != callback:
                callback()

    def _validate(self, classname: str) -> bool:
        """ 校验 """
        if not classname:
            Messagebox.show_error("班级名称不能为空", title="提示", parent=self)
            return False

        count = Clazz.select().where(Clazz.name == classname).count()
        if count > 0:
            Messagebox.show_error("班级名称重复", title="提示", parent=self)
            return False
        
        return True

class StudentDialog(ttk.Toplevel):
    """ 学生管理对话框， 提供添加学生和管理学生对话框 """

    def __init__(self, title="ttkbootstrap", type: Opr=Opr.INSERT, cls: Clazz=None, stu: Student=None, callback=None, iconphoto='', size=None, position=None, minsize=None, maxsize=None, resizable=None, transient=None, overrideredirect=False, windowtype=None, topmost=False, toolwindow=False, alpha=1, **kwargs):
        """
            参数说明：
                type (Opr)：枚举，对话框类型，默认为 INSERT
                cls (Clazz)：学生对应的班级信息
                stu (Student)：学生信息，只有当 isupdate=True 时有效
                callback (function)：回调函数，用于成功后执行自定义操作
        """
        super().__init__(title, iconphoto, size, position, minsize, maxsize, resizable, transient, overrideredirect, windowtype, topmost, toolwindow, alpha, **kwargs)
        if Opr.INSERT == type:
            self._add_student_dialog(cls=cls, callback=callback)
        elif Opr.UPDATE == type:
            self._update_student_dialog(stu=stu, callback=callback)
    
    def _add_student_dialog(self, cls: Clazz=None, callback=None):
        """ 添加学生对话框 """
        row_frame = ttk.Frame(self)
        row_frame.pack(fill=X, pady=1)
        ttk.Label(row_frame, text="学号").pack(side=LEFT, padx=20, pady=20)
        stuno_ent = ttk.Entry(row_frame)
        stuno_ent.pack(side=LEFT)

        row_frame = ttk.Frame(self)
        row_frame.pack(fill=X, pady=1)
        ttk.Label(row_frame, text="姓名").pack(side=LEFT, padx=20, pady=10)
        name_ent = ttk.Entry(row_frame)
        name_ent.pack(side=LEFT)

        row_frame = ttk.Frame(self)
        row_frame.pack(fill=X, pady=1)
        ttk.Label(row_frame, text="班级名称").pack(side=LEFT, padx=20, pady=10)
        clsname_ent = ttk.Entry(row_frame)
        clsname_ent.pack(side=LEFT)
        clsname_ent.insert(0, cls.name)
        clsname_ent.configure(state=READONLY)

        row_frame = ttk.Frame(self)
        row_frame.pack(fill=X, pady=1)
        ttk.Label(row_frame, text="出生日期").pack(side=LEFT, padx=20, pady=10)
        birth_ent = ttk.DateEntry(row_frame, dateformat=r"%Y-%m-%d",)
        birth_ent.pack(side=LEFT)

        row_frame = ttk.Frame(self)
        row_frame.pack(fill=X, pady=1)
        ttk.Label(row_frame, text="性别").pack(side=LEFT, padx=20, pady=10)
        gender_combo = ttk.Combobox(row_frame)
        gender_combo["values"] = ("请选择", "男", "女")
        gender_combo.current(0)
        gender_combo.pack(side=LEFT)
        gender_combo.configure(state=READONLY)

        row_frame = ttk.Frame(self)
        row_frame.pack(fill=X, pady=1)
        ttk.Label(row_frame, text="联系方式").pack(side=LEFT, padx=20, pady=10)
        phone_ent = ttk.Entry(row_frame)
        phone_ent.pack(side=LEFT)

        buttonbar = ttk.Frame(self)
        buttonbar.pack(fill=X, pady=1, side=BOTTOM)
        btn = ttk.Button(
            master=buttonbar,
            text="取消",
            style=SECONDARY,
            command=self.destroy
        )
        btn.pack(side=RIGHT, ipadx=5, ipady=5, padx=(10, 15))
        btn = ttk.Button(
            master=buttonbar,
            text="确定",
            command=lambda: self._save(stu=Student(
                stuno=stuno_ent.get(),
                name=name_ent.get(),
                clazzid=cls.id,
                clazzname=cls.name,
                birth=birth_ent.entry.get(),
                gender=gender_combo.get(),
                phone=phone_ent.get()
            ), callback=callback)
        )
        btn.pack(side=RIGHT, ipadx=5, ipady=5, padx=(2, 0))

    def _query_student_cout_by_clazzid(self, clazzid: int=None) -> int:
        """ 根据班级id查询该班级下学生人数 """
        return Student.select().where(Student.clazzid == clazzid).count()

    def _save(self, stu: Student=None, callback=None):
        """ 保存学生 """
        if self._validate(stu):
            stu.save()
            count = self._query_student_cout_by_clazzid(stu.clazzid)
            qry = Clazz.update({Clazz.number: count}).where(Clazz.id==stu.clazzid)
            qry.execute()

            Messagebox.ok("添加学生成功", title="消息", parent=self)
            self.destroy()

            if None != callback:
                callback()

    def _update_student_dialog(self, stu: Student=None, callback=None):
        """ 修改学生对话框 """
        row_frame = ttk.Frame(self)
        row_frame.pack(fill=X, pady=1)
        ttk.Label(row_frame, text="学号").pack(side=LEFT, padx=20, pady=20)
        stuno_ent = ttk.Entry(row_frame)
        stuno_ent.pack(side=LEFT)
        stuno_ent.insert(0, stu.stuno)

        row_frame = ttk.Frame(self)
        row_frame.pack(fill=X, pady=1)
        ttk.Label(row_frame, text="姓名").pack(side=LEFT, padx=20, pady=10)
        name_ent = ttk.Entry(row_frame)
        name_ent.pack(side=LEFT)
        name_ent.insert(0, stu.name)

        row_frame = ttk.Frame(self)
        row_frame.pack(fill=X, pady=1)
        ttk.Label(row_frame, text="班级名称").pack(side=LEFT, padx=20, pady=10)
        clsname_ent = ttk.Entry(row_frame)
        clsname_ent.pack(side=LEFT)
        clsname_ent.insert(0, stu.clazzname)
        clsname_ent.configure(state=READONLY)

        row_frame = ttk.Frame(self)
        row_frame.pack(fill=X, pady=1)
        ttk.Label(row_frame, text="出生日期").pack(side=LEFT, padx=20, pady=10)
        birth_ent = ttk.DateEntry(row_frame, dateformat=r"%Y-%m-%d", startdate=stu.birth)
        birth_ent.pack(side=LEFT)

        gender_options = ("请选择", "男", "女")
        row_frame = ttk.Frame(self)
        row_frame.pack(fill=X, pady=1)
        ttk.Label(row_frame, text="性别").pack(side=LEFT, padx=20, pady=10)
        gender_combo = ttk.Combobox(row_frame)
        gender_combo["values"] = gender_options
        gender_combo.current(gender_options.index(stu.gender))
        gender_combo.pack(side=LEFT)
        gender_combo.configure(state=READONLY)

        row_frame = ttk.Frame(self)
        row_frame.pack(fill=X, pady=1)
        ttk.Label(row_frame, text="联系方式").pack(side=LEFT, padx=20, pady=10)
        phone_ent = ttk.Entry(row_frame)
        phone_ent.pack(side=LEFT)
        phone_ent.insert(0, stu.phone)

        buttonbar = ttk.Frame(self)
        buttonbar.pack(fill=X, pady=1, side=BOTTOM)
        btn = ttk.Button(
            master=buttonbar,
            text="取消",
            style=SECONDARY,
            command=self.destroy
        )
        btn.pack(side=RIGHT, ipadx=5, ipady=5, padx=(10, 15))
        btn = ttk.Button(
            master=buttonbar,
            text="确定",
            command=lambda: self._update(stu=Student(
                id=stu.id,
                stuno=stuno_ent.get(),
                name=name_ent.get(),
                clazzid=stu.clazzid,
                clazzname=stu.clazzname,
                birth=birth_ent.entry.get(),
                gender=gender_combo.get(),
                phone=phone_ent.get()
            ), callback=callback)
        )
        btn.pack(side=RIGHT, ipadx=5, ipady=5, padx=(2, 0))

    def _update(self, stu: Student=None, callback=None):
        """ 修改学生 """
        if self._validate(stu):
            stu.save()
            Messagebox.ok("修改学生成功", title="消息", parent=self)
            self.destroy()

            if None != callback:
                callback()

    def _validate(self, stu: Student=None) -> bool:
        """ 校验 """
        if not stu.stuno:
            Messagebox.show_error("学号不能为空", title="提示", parent=self)
            return False
        if not stu.name:
            Messagebox.show_error("学生姓名不能为空", title="提示", parent=self)
            return False
        if not stu.birth:
            Messagebox.show_error("出生日期不能为空", title="提示", parent=self)
            return False
        if stu.gender == "请选择":
            Messagebox.show_error("请选择学生性别", title="提示", parent=self)
            return False
        if not stu.phone:
            Messagebox.show_error("联系方式不能为空", title="提示", parent=self)
            return False

        return True